home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / file / managers / mc-3.2 / mc-3 / mc-3.2.1 / vfs / mcserv.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-17  |  22.6 KB  |  1,101 lines

  1. /* Server for the Midnight Commander Virtual File System.
  2.    
  3.    Copyright (C) 1995 Miguel de Icaza
  4.    
  5.    This program is free software; you can redistribute it and/or modify
  6.    it under the terms of the GNU General Public License as published by
  7.    the Free Software Foundation; either version 2 of the License, or
  8.    (at your option) any later version.
  9.    
  10.    This program is distributed in the hope that it will be useful,
  11.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.    GNU General Public License for more details.
  14.  
  15.    You should have received a copy of the GNU General Public License
  16.    along with this program; if not, write to the Free Software
  17.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  
  19.    TODO:
  20.    opendir instead of keeping its table of file handles could return
  21.    the pointer and expect the client to send a proper value back each
  22.    time :-)
  23.  
  24.    We should use syslog to register login/logout.
  25.    
  26.     */
  27.  
  28. /* {{{ Includes and global variables */
  29.  
  30. #include <config.h>
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #ifdef HAVE_UNISTD_H
  34. #include <unistd.h>
  35. #endif
  36. #include <fcntl.h>
  37. #include <string.h>
  38. #ifdef HAVE_LIMITS_H
  39. #include <limits.h>
  40. #endif
  41. #ifndef NGROUPS_MAX
  42. #include <sys/param.h>
  43. #ifdef NGROUPS
  44. #define NGROUPS_MAX NGROUPS
  45. #endif
  46. #endif
  47. #ifdef HAVE_GRP_H
  48. #include <grp.h>
  49. #endif
  50. #ifdef HAVE_SHADOW_H
  51. #include <shadow.h>
  52. #else
  53. #ifdef HAVE_SHADOW_SHADOW_H
  54. #include <shadow/shadow.h>
  55. #endif
  56. #endif
  57. #ifdef HAVE_CRYPT_H
  58. #include <crypt.h>
  59. #endif
  60. #include <sys/types.h>
  61. #include <sys/stat.h>
  62. #include <errno.h>
  63. #include <signal.h>
  64. #include <time.h>
  65.  
  66. /* Network include files */
  67. #include <sys/socket.h>
  68. #include <netinet/in.h>
  69. #include <netdb.h>
  70. #include <arpa/inet.h>
  71. #ifdef HAVE_PMAP_SET
  72. #include <rpc/rpc.h>
  73. #include <rpc/pmap_prot.h>
  74. #ifdef HAVE_RPC_PMAP_CLNT_H
  75. #include <rpc/pmap_clnt.h>
  76. #endif
  77. #endif
  78.  
  79. /* Authentication include files */
  80. #include <pwd.h>
  81.  
  82. #include "../src/fs.h"
  83. #include "../src/mem.h"
  84. #include "mcfs.h"
  85. #include "tcputil.h"
  86.  
  87. /* The socket from which we accept commands */
  88. int msock;
  89.  
  90. /* If non zero, we accept further commands */
  91. int logged_in = 0;
  92.  
  93. /* Home directory */
  94. char *home_dir = NULL;
  95.  
  96. char *up_dir = NULL;
  97.  
  98. /* Were we started from inetd? */
  99. int  inetd_started = 0;
  100.  
  101. /* Are we running as a daemon? */
  102. int  isDaemon = 0;
  103.  
  104. /* guess */
  105. int verbose = 0;
  106.  
  107. /* ftp auth */
  108. int ftp = 0;
  109.  
  110. /* port number in which we listen to connections,
  111.  * if zero, we try to contact the portmapper to get a port, and
  112.  * if it's not possible, then we use a hardcoded value
  113.  */
  114. int portnum = 0;
  115.  
  116. /* if the server will use rcmd based authentication (hosts.equiv .rhosts) */
  117. int r_auth = 0;
  118.  
  119. #define OPENDIR_HANDLES 8
  120.  
  121. char buffer [4096];
  122. int debug = 1;
  123.  
  124. /* }}} */
  125.  
  126. /* {{{ Misc routines */
  127.  
  128. void send_status (int status, int errno_number)
  129. {
  130.     rpc_send (msock, RPC_INT, status, RPC_INT, errno_number, RPC_END);
  131. }
  132.  
  133. /* }}} */
  134.  
  135. /* {{{ File with handle operations */
  136.  
  137. void do_open (void)
  138. {
  139.     int handle, flags, mode;
  140.     char *arg;
  141.  
  142.     rpc_get (msock, RPC_STRING, &arg, RPC_INT, &flags, RPC_INT, &mode,RPC_END);
  143.     
  144.     handle = open (arg, flags, mode);
  145.     send_status (handle, errno);
  146.     free (arg);
  147. }
  148.  
  149. void do_read (void)
  150. {
  151.     int handle, count, n;
  152.     void *data;
  153.    
  154.     rpc_get (msock, RPC_INT, &handle, RPC_INT, &count, RPC_END);
  155.     data = malloc (count);
  156.     if (!data){
  157.     send_status (-1, ENOMEM);
  158.     return;
  159.     }
  160.     if (verbose) printf ("count=%d\n", count);
  161.     n = read (handle, data, count);
  162.     if (verbose) printf ("result=%d\n", n);
  163.     if (n < 0){
  164.     send_status (-1, errno);
  165.     return;
  166.     }
  167.     send_status (n, 0);
  168.     rpc_send (msock, RPC_BLOCK, n, data, RPC_END);
  169.     
  170.     free (data);
  171. }
  172.  
  173. void do_write (void)
  174. {
  175.     int handle, count, status;
  176.     char buffer [8192];
  177.     
  178.     rpc_get (msock, RPC_INT, &handle, RPC_INT, &count, RPC_END);
  179.     status = 0;
  180.     while (count){
  181.     int nbytes = count > 8192 ? 8192 : count;
  182.     
  183.     rpc_get (msock, RPC_BLOCK, nbytes, buffer, RPC_END);
  184.     status = write (handle, buffer, nbytes);
  185.     count -= nbytes;
  186.     }
  187.     send_status (status, errno);
  188. }
  189.  
  190. void do_lseek (void)
  191. {
  192.     int handle, offset, whence;
  193.  
  194.     rpc_get (msock,
  195.          RPC_INT, &handle,
  196.          RPC_INT, &offset,
  197.          RPC_INT, &whence, RPC_END);
  198.     send_status (lseek (handle, offset, whence), errno);
  199. }
  200.  
  201. void do_close (void)
  202. {
  203.     int handle;
  204.     
  205.     rpc_get (msock, RPC_INT, &handle, RPC_END);
  206.     send_status (close (handle), errno);
  207. }
  208.  
  209. /* }}} */
  210.  
  211. /* {{{ Stat family routines */
  212.  
  213. void send_time (int sock, time_t time)
  214. {
  215.     char   *ct;
  216.     int    month;
  217.     
  218.     ct = ctime (&time);
  219.     ct [3] = ct [10] = ct [13] = ct [16] = ct [19] = 0;
  220.     
  221.     /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
  222.     if (ct [4] == 'J'){
  223.     if (ct [5] == 'a'){
  224.         month = 0;
  225.     } else
  226.         month = (ct [6] == 'n') ? 5 : 6;
  227.     } else if (ct [4] == 'F'){
  228.     month = 1;
  229.     } else if (ct [4] == 'M'){
  230.     month = (ct [6] == 'r') ? 2 : 5;
  231.     } else if (ct [4] == 'A'){
  232.     month = (ct [5] == 'p') ? 3 : 7;
  233.     } else if (ct [4] == 'S'){
  234.     month = 8;
  235.     } else if (ct [4] == 'O'){
  236.     month = 9;
  237.     } else if (ct [4] == 'N'){
  238.     month = 10;
  239.     } else
  240.     month = 11;
  241.     rpc_send (msock,
  242.           RPC_INT, atoi (&ct [17]),      /* sec */
  243.           RPC_INT, atoi (&ct [14]),         /* min */
  244.           RPC_INT, atoi (&ct [11]),         /* hour */
  245.             RPC_INT, atoi (&ct [8]),          /* mday */
  246.               RPC_INT, atoi (&ct [20]),         /* year */
  247.               RPC_INT, month,                    /* month */
  248.           RPC_END);
  249. }
  250.  
  251. void send_stat_info (struct stat *st)
  252. {
  253.     int mylong;
  254.     int blocks =
  255. #ifdef HAVE_ST_BLOCKS
  256.     st->st_blocks;
  257. #else
  258.         st->st_size / 1024;
  259. #endif
  260.     
  261.     mylong = st->st_dev;
  262.     rpc_send (msock, RPC_INT, (long) st->st_dev, 
  263.           RPC_INT, (long) st->st_ino,
  264.           RPC_INT, (long) st->st_mode,
  265.           RPC_INT, (long) st->st_nlink,
  266.           RPC_INT, (long) st->st_uid,
  267.           RPC_INT, (long) st->st_gid,
  268.           RPC_INT, (long) st->st_size,
  269.           RPC_INT, (long) blocks, RPC_END);
  270.     send_time (msock, st->st_atime);
  271.     send_time (msock, st->st_mtime);
  272.     send_time (msock, st->st_ctime);
  273. }
  274.  
  275. void do_lstat ()
  276. {
  277.     struct stat st;
  278.     char   *file;
  279.     int    n;
  280.  
  281.     rpc_get (msock, RPC_STRING, &file, RPC_END);
  282.     n = lstat (file, &st);
  283.     send_status (n, errno);
  284.     if (n >= 0)
  285.     send_stat_info (&st);
  286.     free (file);
  287. }
  288.  
  289. void do_fstat (void)
  290. {
  291.     int handle;
  292.     int n;
  293.     struct stat st;
  294.    
  295.     rpc_get (msock, RPC_INT, &handle, RPC_END);
  296.     n = fstat (handle, &st);
  297.     send_status (n, errno);
  298.     if (n < 0)
  299.     return;
  300.  
  301.     send_stat_info (&st);
  302. }
  303.  
  304. void do_stat ()
  305. {
  306.     struct stat st;
  307.     int    n;
  308.     char   *file;
  309.  
  310.     rpc_get (msock, RPC_STRING, &file, RPC_END);
  311.  
  312.     n = stat (file, &st);
  313.     send_status (n, errno);
  314.     if (n >= 0)
  315.     send_stat_info (&st);
  316.     free (file);
  317. }
  318.  
  319. /* }}} */
  320.  
  321. /* {{{ Directory lookup operations */
  322.  
  323. static struct {
  324.     int used;
  325.     DIR *dirs [OPENDIR_HANDLES];
  326. } mcfs_DIR;
  327.  
  328. void close_handle (int handle)
  329. {
  330.     mcfs_DIR.used--;
  331.     if (mcfs_DIR.dirs [handle])
  332.     closedir (mcfs_DIR.dirs [handle]);
  333.     mcfs_DIR.dirs [handle] = 0;
  334. }
  335.  
  336. void do_opendir (void)
  337. {
  338.     int handle, i;
  339.     char *arg;
  340.     DIR *p;
  341.  
  342.     if (mcfs_DIR.used == OPENDIR_HANDLES){
  343.     send_status (-1, errno);    /* Error */
  344.     return;
  345.     }
  346.  
  347.     rpc_get (msock, RPC_STRING, &arg, RPC_END);
  348.     
  349.     handle = -1;
  350.     for (i = 0; i < OPENDIR_HANDLES; i++){
  351.     if (mcfs_DIR.dirs [i] == 0){
  352.         handle = i;
  353.         break;
  354.     }
  355.     }
  356.  
  357.     if (handle == -1){
  358.     send_status (-1, errno);
  359.     return;
  360.     }
  361.  
  362.     if (verbose) printf ("handle=%d\n", handle);
  363.     p = opendir (arg);
  364.     if (p){
  365.     mcfs_DIR.dirs [handle] = p;
  366.         mcfs_DIR.used ++;
  367.  
  368.     /* Because 0 is an error value */
  369.     rpc_send (msock, RPC_INT, handle+1, RPC_INT, 0, RPC_END);
  370.  
  371.     } else
  372.     send_status (-1, errno);
  373.     
  374.     free (arg);
  375. }
  376.  
  377. /* Sends the complete directory listing, as well as the stat information */
  378. void do_readdir (void)
  379. {
  380.     struct dirent *dirent;
  381.     struct stat st;
  382.     int    handle, n;
  383.  
  384.     rpc_get (msock, RPC_INT, &handle, RPC_END);
  385.     
  386.     if (!handle){
  387.     rpc_send (msock, RPC_INT, 0, RPC_END);
  388.     return;
  389.     }
  390.  
  391.     /* We incremented it in opendir */
  392.     handle --;
  393.  
  394.     while ((dirent = readdir (mcfs_DIR.dirs [handle]))){
  395.     int length = NLENGTH (dirent);
  396.  
  397.     rpc_send (msock, RPC_INT, length, RPC_END);
  398.     rpc_send (msock, RPC_BLOCK, length, dirent->d_name, RPC_END);
  399.     n = lstat (dirent->d_name, &st);
  400.     send_status (n, errno);
  401.     if (n >= 0)
  402.         send_stat_info (&st);
  403.     }
  404.     close_handle (handle);
  405.     rpc_send (msock, RPC_INT, 0, RPC_END);
  406. }
  407.  
  408. void do_closedir (void)
  409. {
  410.     int handle;
  411.  
  412.     rpc_get (msock, RPC_INT, &handle, RPC_END);
  413.     close_handle (handle-1);
  414. }
  415.  
  416. /* }}} */
  417.  
  418. /* {{{ Operations with one and two file name argument */
  419.  
  420. void do_chdir (void)
  421. {
  422.     char *file;
  423.  
  424.     rpc_get (msock, RPC_STRING, &file, RPC_END);
  425.     
  426.     send_status (chdir (file), errno);
  427.     free (file);
  428. }
  429.  
  430. void do_rmdir (void)
  431. {
  432.     char *file;
  433.  
  434.     rpc_get (msock, RPC_STRING, &file, RPC_END);
  435.     
  436.     send_status (rmdir (file), errno);
  437.     free (file);
  438. }
  439.  
  440. void do_mkdir (void)
  441. {
  442.     char *file;
  443.     int  mode;
  444.  
  445.     rpc_get (msock, RPC_STRING, &file, RPC_INT, &mode, RPC_END);
  446.     
  447.     send_status (mkdir (file, mode), errno);
  448.     free (file);
  449. }
  450.  
  451. void do_mknod (void)
  452. {
  453.     char *file;
  454.     int  mode, dev;
  455.  
  456.     rpc_get (msock, RPC_STRING, &file, RPC_INT, &mode, RPC_INT, &dev, RPC_END);
  457.     
  458.     send_status (mknod (file, mode, dev), errno);
  459.     free (file);
  460. }
  461.  
  462. void do_readlink (void)
  463. {
  464.     char buffer [2048];
  465.     char *file;
  466.     int  n;
  467.  
  468.     rpc_get (msock, RPC_STRING, &file, RPC_END);
  469.     n = readlink (file, buffer, 2048);
  470.     send_status (n, errno);
  471.     buffer [n] = 0;
  472.     if (n >= 0)
  473.     rpc_send (msock, RPC_STRING, buffer, RPC_END);
  474.  
  475.     free (file);
  476. }
  477.  
  478. void do_unlink (void)
  479. {
  480.     char *file;
  481.     
  482.     rpc_get (msock, RPC_STRING, &file, RPC_END);
  483.     send_status (unlink (file), errno);
  484.     free (file);
  485. }
  486.  
  487. void do_rename (void)
  488. {
  489.     char *f1, *f2;
  490.     
  491.     rpc_get (msock, RPC_STRING, &f1, RPC_STRING, &f2, RPC_END);
  492.     send_status (rename (f1, f2), errno);
  493.     free (f1); free (f2);
  494. }
  495.  
  496. void do_symlink (void)
  497. {
  498.     char *f1, *f2;
  499.     
  500.     rpc_get (msock, RPC_STRING, &f1, RPC_STRING, &f2, RPC_END);
  501.     send_status (symlink (f1, f2), errno);
  502.     free (f1); free (f2);
  503. }
  504.  
  505. void do_link (void)
  506. {
  507.     char *f1, *f2;
  508.     
  509.     rpc_get (msock, RPC_STRING, &f1, RPC_STRING, &f2, RPC_END);
  510.     send_status (link (f1, f2), errno);
  511.     free (f1); free (f2);
  512. }
  513.  
  514.  
  515. /* }}} */
  516.  
  517. /* {{{ Misc commands */
  518.  
  519. void do_gethome (void)
  520. {
  521.     rpc_send (msock, RPC_STRING, (home_dir) ? home_dir : "/", RPC_END);
  522. }
  523.  
  524. void do_getupdir (void)
  525. {
  526.     rpc_send (msock, RPC_STRING, (up_dir) ? up_dir : "/", RPC_END);
  527. }
  528.  
  529. void do_chmod (void)
  530. {
  531.     char *file;
  532.     int  mode;
  533.     
  534.     rpc_get (msock, RPC_STRING, &file, RPC_INT, &mode, RPC_END);
  535.     send_status (chmod (file, mode), errno);
  536.     free (file);
  537. }
  538.  
  539. void do_chown (void)
  540. {
  541.     char *file;
  542.     int  owner, group;
  543.     
  544.     rpc_get (msock, RPC_STRING, &file,RPC_INT, &owner, RPC_INT,&group,RPC_END);
  545.     send_status (chown (file, owner, group), errno);
  546.     free (file);
  547. }
  548.  
  549. void do_quit ()
  550. {
  551.     exit (1);
  552. }
  553.  
  554. /* Keep reading until we find a \n */
  555. static int next_line (int socket)
  556. {
  557.     char c;
  558.  
  559.     while (1){
  560.     if (read (socket, &c, 1) <= 0)
  561.         return 0;
  562.     if (c == '\n')
  563.         return 1;
  564.     }
  565. }
  566.  
  567. static int ftp_answer (int sock, char *text)
  568. {
  569.     char answer [4];
  570.  
  571.     next_line (sock);
  572.     socket_read_block (sock, answer, 3);
  573.     answer [3] = 0;
  574.     if (strcmp (answer, text) == 0)
  575.     return 1;
  576.     return 0;
  577. }
  578.  
  579. int do_ftp_auth (char *username, char *password)
  580. {
  581.     struct   sockaddr_in local_address;
  582.     unsigned long inaddr;
  583.     int      my_socket;
  584.     char     answer [4];
  585.  
  586.     bzero ((char *) &local_address, sizeof (local_address));
  587.     
  588.     local_address.sin_family = AF_INET;
  589.     /* FIXME: extract the ftp port with the proper function */
  590.     local_address.sin_port   = htons (21);
  591.  
  592.     /*  Convert localhost to usable format */
  593.     if ((inaddr = inet_addr ("127.0.0.1")) != -1)
  594.     bcopy ((char *) &inaddr, (char *) &local_address.sin_addr,
  595.            sizeof (inaddr));
  596.     
  597.     if ((my_socket = socket (AF_INET, SOCK_STREAM, 0)) < 0){
  598.     if (!isDaemon) fprintf (stderr, "do_auth: can't create socket\n");
  599.     return 0;
  600.     }
  601.     if (connect (my_socket, (struct sockaddr *) &local_address,
  602.          sizeof (local_address)) < 0){
  603.     fprintf (stderr,
  604.          "do_auth: can't connect to ftp daemon for authentication\n");
  605.     close (my_socket);
  606.     return 0;
  607.     }
  608.     send_string (my_socket, "user ");
  609.     send_string (my_socket, username);
  610.     send_string (my_socket, "\r\n");
  611.     if (!ftp_answer (my_socket, "331")){
  612.     send_string (my_socket, "quit\r\n");
  613.     close (my_socket);
  614.     return 0;
  615.     }
  616.     next_line (my_socket);    /* Eat all the line */
  617.     send_string (my_socket, "pass ");
  618.     send_string (my_socket, password);
  619.     send_string (my_socket, "\r\n");
  620.     socket_read_block (my_socket, answer, 3);
  621.     answer [3] = 0;
  622.     send_string (my_socket, "\r\n");
  623.     send_string (my_socket, "quit\r\n");
  624.     close (my_socket);
  625.     if (strcmp (answer, "230") == 0)
  626.     return 1;
  627.     return 0;
  628. }
  629.  
  630. int do_classic_auth (char *username, char *password)
  631. {
  632.     struct passwd *this;
  633.     int ret;
  634. #ifdef LINUX_SHADOW
  635.     struct spwd *spw;
  636.     extern char *pw_encrypt (char *, char *);
  637. #else
  638. #ifdef NEED_CRYPT_PROTOTYPE
  639.     extern char *crypt (const char *, const char *);
  640. #endif
  641. #endif
  642.     
  643.     if ((this = getpwnam (username)) == 0)
  644.     return 0;
  645.  
  646. #ifdef LINUX_SHADOW
  647.     if ((spw = getspnam (username)) == NULL)
  648.         this->pw_passwd = "*";
  649.     else
  650.         this->pw_passwd = spw->sp_pwdp;
  651.     if (strcmp (pw_encrypt (password, this->pw_passwd), this->pw_passwd) == 0)
  652.         ret = 1;
  653.     else
  654.         ret = 0;
  655. #else    
  656. #ifdef HAVE_CRYPT    
  657.     if (strcmp (crypt (password, this->pw_passwd), this->pw_passwd) == 0){
  658.     ret = 1;
  659.     } else
  660. #endif
  661.     {
  662.     ret = 0;
  663.     }
  664. #endif
  665.     endpwent ();
  666.     return ret;
  667. }
  668.  
  669. /* Try to authenticate the user based on:
  670.    - pwdauth if the system supports it.
  671.    - conventional auth (check salt on /etc/passwd, crypt, and compare
  672.    - try to contact the local ftp server and login
  673. */
  674. int do_auth (char *username, char *password)
  675. {
  676.     int auth = 0;
  677.     struct passwd *this;
  678.     
  679.     if (strcmp (username, "anonymous") == 0)
  680.     username = "ftp";
  681.     
  682. #ifdef HAVE_PWDAUTH
  683.     if (pwdauth (username, password) == 0)
  684.     auth = 1;
  685. #endif
  686.     else
  687.     if (do_classic_auth (username, password))
  688.     auth = 1;
  689.     else if (ftp)
  690.     auth = do_ftp_auth (username, password);
  691.     
  692.     if (!auth)
  693.         return 0;
  694.     
  695.     this = getpwnam (username);
  696.     if (this == 0)
  697.     return 0;
  698.  
  699.     if (chdir (this->pw_dir) == -1)
  700.         return 0;
  701.     
  702.     if (this->pw_dir [strlen (this->pw_dir) - 1] == '/')
  703.         home_dir = strdup (this->pw_dir);
  704.     else {
  705.         home_dir = malloc (strlen (this->pw_dir) + 2);
  706.         if (home_dir) {
  707.             strcpy (home_dir, this->pw_dir);
  708.             strcat (home_dir, "/");
  709.         } else
  710.             home_dir = "/";
  711.     }
  712.         
  713.     
  714.     if (setgid (this->pw_gid) == -1)
  715.         return 0;
  716.     
  717. #ifdef HAVE_INITGROUPS
  718. #ifdef NGROUPS_MAX
  719.     if (NGROUPS_MAX > 1 && initgroups (this->pw_name, this->pw_gid))
  720.         return 0;
  721. #endif
  722. #endif    
  723.  
  724. #ifndef BSD
  725.     if (setuid (this->pw_uid))
  726. #else
  727.     if (setreuid (this->pw_uid, this->pw_uid))
  728. #endif
  729.         return 0;
  730.  
  731.     /* If the setuid call failed, then deny access */
  732.     /* This should fix the problem on those machines with strange setups */
  733.     if (getuid () != this->pw_uid)
  734.     return 0;
  735.     
  736.     if (strcmp (username, "ftp") == 0)
  737.     chroot (this->pw_dir);
  738.  
  739.     endpwent ();
  740.     return auth;
  741. }
  742.  
  743. #if 0
  744. int do_rauth (int socket)
  745. {
  746.     struct sockaddr_in from;
  747.     struct hostent *hp;
  748.     
  749.     if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0)
  750.     return 0;
  751.     from.sin_port = ntohs ((unsigned short) from.sin_port);
  752.  
  753.     /* Strange, this should not happend */
  754.     if (from.sin_family != AF_INET)
  755.     return 0;
  756.  
  757.     hp = gethostbyaddr((char *)&fromp.sin_addr, sizeof (struct in_addr),
  758.                fromp.sin_family);
  759.     
  760. }
  761. #endif
  762.  
  763. int do_rauth (int msock)
  764. {
  765.     return 0;
  766. }
  767.  
  768. void login_reply (int logged_in)
  769. {
  770.     rpc_send (msock, RPC_INT,
  771.           logged_in ? MC_LOGINOK : MC_INVALID_PASS,
  772.           RPC_END);
  773. }
  774.  
  775. /* FIXME: Implement the anonymous login */
  776. void do_login ()
  777. {
  778.     char *username;
  779.     char *password;
  780.     int  result;
  781.     
  782.     rpc_get (msock, RPC_STRING, &up_dir, RPC_STRING, &username, RPC_END);
  783.     if (verbose) printf ("username: %s\n", username);
  784.     
  785.     if (r_auth){
  786.     logged_in = do_rauth (msock);
  787.     if (logged_in){
  788.         login_reply (logged_in);
  789.         return;
  790.     }
  791.     }
  792.     rpc_send (msock, RPC_INT, MC_NEED_PASSWORD, RPC_END);
  793.     rpc_get (msock, RPC_INT, &result, RPC_END);
  794.     if (result == MC_QUIT)
  795.     exit (0);
  796.     if (result != MC_PASS){
  797.     if (verbose) printf ("do_login: Unknown response: %d\n", result);
  798.     exit (0);
  799.     }
  800.     rpc_get (msock, RPC_STRING, &password, RPC_END);
  801.     logged_in = do_auth (username, password);
  802.     endpwent ();
  803.     login_reply (logged_in);
  804. }
  805.  
  806. /* }}} */
  807.  
  808. /* {{{ Server and dispatching functions */
  809.  
  810. /* This structure must be kept in synch with mcfs.h enums */
  811.  
  812. struct {
  813.     char *command;
  814.     void (*callback)(void);
  815. } commands [] = {
  816.     { "open",       do_open },
  817.     { "close",      do_close },
  818.     { "read",       do_read },
  819.     { "write",      do_write },
  820.     { "opendir",    do_opendir }, 
  821.     { "readdir",    do_readdir },
  822.     { "closedir",   do_closedir },
  823.     { "stat ",      do_stat },
  824.     { "lstat ",     do_lstat },
  825.     { "fstat",      do_fstat },
  826.     { "chmod",      do_chmod },
  827.     { "chown",      do_chown },
  828.     { "readlink ",  do_readlink },
  829.     { "unlink",     do_unlink },
  830.     { "rename",     do_rename },
  831.     { "chdir ",     do_chdir },
  832.     { "lseek",      do_lseek },
  833.     { "rmdir",      do_rmdir },
  834.     { "symlink",    do_symlink },
  835.     { "mknod",      do_mknod },
  836.     { "mkdir",      do_mkdir },
  837.     { "link",       do_link },
  838.     { "gethome",    do_gethome },
  839.     { "getupdir",   do_getupdir },
  840.     { "login",      do_login },
  841.     { "quit",       do_quit }
  842. };
  843.  
  844. void exec_command (int command)
  845. {
  846.     if (commands [command].command == 0){
  847.     fprintf (stderr, "Got unknown command: %d\n", command);
  848.     exit (1);
  849.     }
  850.     if (verbose) printf ("Command: %s\n", commands [command].command);
  851.     (*commands [command].callback)();
  852. }
  853.  
  854. void check_version ()
  855. {
  856.     int version;
  857.     
  858.     rpc_get (msock, RPC_INT, &version, RPC_END);
  859.     if (version == 1)
  860.     rpc_send (msock, RPC_INT, MC_VERSION_OK, RPC_END);
  861.     else
  862.     rpc_send (msock, RPC_INT, MC_VERSION_MISMATCH);
  863. }
  864.  
  865. /* This routine is called by rpc_get/rpc_send when the connection is closed */
  866. void tcp_invalidate_socket (int sock)
  867. {
  868.     printf ("Connection closed\n");
  869.     exit (1);
  870. }
  871.  
  872. void server (int sock)
  873. {
  874.     int command;
  875.     
  876.     msock = sock;
  877.  
  878.     check_version ();
  879.     for (;;){
  880.     rpc_get (sock, RPC_INT, &command, RPC_END);
  881.     if (logged_in || command == MC_LOGIN)
  882.         exec_command (command);
  883.     }
  884. }
  885.  
  886. /* }}} */
  887.  
  888. /* {{{ Net support code */
  889.  
  890. char *get_client (int portnum)
  891. {
  892.     int sock, clilen, newsocket;
  893.     struct sockaddr_in client_address, server_address;
  894.     struct hostent *hp;
  895.     char hostname [255];
  896.     int yes = 1;
  897.     
  898.     if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0)
  899.     return "Can't create socket";
  900.  
  901.     /* Use this to debug: */
  902.     if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (char *) &yes, sizeof (yes)) < 0)
  903.     return "setsockopt failed";
  904.  
  905.     gethostname (hostname, 255);
  906.     if (verbose) printf ("hostname=%s\n", hostname);
  907.     hp = gethostbyname (hostname);
  908.     if (hp == 0)
  909.     return "hp = 0!";
  910.     
  911.     bzero ((char *) &server_address, sizeof (server_address));
  912.     server_address.sin_family = hp->h_addrtype;
  913.     server_address.sin_addr.s_addr = htonl (INADDR_ANY);
  914.     server_address.sin_port = htons (portnum);
  915.  
  916.     if (bind (sock, (struct sockaddr *) &server_address,
  917.           sizeof (server_address)) < 0)
  918.     return "Can't bind";
  919.  
  920.     listen (sock, 5);
  921.  
  922.     for (;;){
  923.     clilen = sizeof (client_address);
  924.  
  925.     if (verbose)
  926.         printf ("Waiting for %sconnection...", isDaemon ? "":"just one ");
  927.     fflush (stdout);
  928.     newsocket = accept (sock, (struct sockaddr *) &client_address,
  929.                 &clilen);
  930.     if (verbose) printf ("ok\n");
  931.     if (isDaemon){
  932.         if (fork ()){
  933.         close (newsocket);
  934.         /* This is needed to avoid zombies */
  935.         if (fork () != 0)
  936.             exit (0);
  937.         } else {
  938.         close (sock);
  939.         server (newsocket);
  940.         exit (0);
  941.         }
  942.     } else {
  943.         server (newsocket);
  944.         close (newsocket);
  945.     }
  946.     }
  947. }
  948.  
  949. #ifdef HAVE_PMAP_SET
  950. void signal_int_handler ()
  951. {
  952.     pmap_unset (RPC_PROGNUM, RPC_PROGVER);
  953. }
  954. #endif
  955.  
  956. #ifndef IPPORT_RESERVED
  957. #define IPPORT_RESERVED 1024;
  958. #endif
  959.  
  960. int get_port_number ()
  961. {
  962.     int port = 0;
  963.  
  964. #ifdef HAVE_RRESVPORT
  965.     int start_port = IPPORT_RESERVED;
  966.     
  967.     port = rresvport (&start_port);
  968.     if (port == -1){
  969.     if (geteuid () == 0){
  970.         fprintf (stderr, "Could not bind the server on a reserved port\n");
  971.         exit (1);
  972.     }
  973.     port = 0;
  974.     }
  975. #endif
  976.     if (port)
  977.     return port;
  978.     
  979.     port = mcserver_port;
  980.  
  981.     return port;
  982. }
  983.  
  984. void register_port (int portnum, int abort_if_fail)
  985. {
  986. #ifdef HAVE_PMAP_SET
  987.     /* Register our service with the portmapper */
  988.     /* protocol: pmap_set (prognum, versnum, protocol, portp) */
  989.     
  990.     if (pmap_set (RPC_PROGNUM, RPC_PROGVER, IPPROTO_TCP, portnum))
  991.     signal (SIGINT, signal_int_handler);
  992.     else {
  993.     fprintf (stderr, "Could not register service with portmapper\n");
  994.     if (abort_if_fail)
  995.         exit (1);
  996.     }
  997. #else
  998.     if (abort_if_fail){
  999.     fprintf (stderr,
  1000.          "This system lacks port registration, try using the -p\n"
  1001.          "flag to force installation at a given port");
  1002.     }
  1003. #endif
  1004. }
  1005.  
  1006. /* }}} */
  1007.  
  1008. int main (int argc, char *argv [])
  1009. {
  1010.     char *result;
  1011.     extern char *optarg;
  1012.     int c;
  1013.  
  1014.     while ((c = getopt (argc, argv, "diqp:v")) != -1){
  1015.     switch (c){
  1016.     case 'd':
  1017.         isDaemon = 1;
  1018.         verbose = 0;
  1019.         break;
  1020.  
  1021.     case 'v':
  1022.         verbose = 1;
  1023.         break;
  1024.         
  1025.     case 'f':
  1026.         ftp = 1;
  1027.         break;
  1028.  
  1029.     case 'q':
  1030.         verbose = 0;
  1031.         break;
  1032.  
  1033.     case 'p':
  1034.         portnum = atoi (optarg);
  1035.         break;
  1036.  
  1037.     case 'i':
  1038.         inetd_started = 1;
  1039.         break;
  1040.  
  1041.     case 'r':
  1042.         r_auth = 1;
  1043.         break;
  1044.         
  1045.     default:
  1046.         fprintf (stderr, "Usage is: mcserv [-diqrv] [-p portnum]\n\n"
  1047.             "-d  become a daemon (sets -q)\n"
  1048.             "-q  quiet mode\n"
  1049.             "-r  use rhost based authentication\n"
  1050.             "-f  force ftp authentication\n"
  1051.             "-v  verbose mode\n"
  1052.             "-p  to specify a port number to listen\n");
  1053.         exit (0);
  1054.         
  1055.     }
  1056.     }
  1057.  
  1058.     if (portnum == 0)
  1059.     portnum = get_port_number ();
  1060.     register_port (portnum, 0);
  1061.  
  1062.     if (verbose)
  1063.     printf ("Using port %d\n", portnum);
  1064.     if ((result = get_client (portnum)))
  1065.     perror (result);
  1066.     return 0;
  1067. }
  1068.  
  1069. /* This functions are not used */
  1070. void message (int is_error, char *text, char *msg)
  1071. {
  1072.     printf ("%s %s\n", text, msg);
  1073. }
  1074.  
  1075. char *unix_error_string (int a)
  1076. {
  1077.     return "none";
  1078. }
  1079.  
  1080. #ifndef HAVE_MAD
  1081. void *do_xmalloc (int size)
  1082. {
  1083.     void *m = malloc (size);
  1084.  
  1085.     if (!m){
  1086.     fprintf (stderr, "memory exhausted\n");
  1087.     exit (1);
  1088.     }
  1089.     return m;
  1090. }
  1091. #endif
  1092.  
  1093. #ifndef HAVE_STRDUP
  1094. char *strdup (char *s)
  1095. {
  1096.     char *t = malloc (strlen (s)+1);
  1097.     strcpy (t, s);
  1098.     return t;
  1099. }
  1100. #endif
  1101.